package demo2;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoServer {
    private ServerSocket socket ;  // 这个socket,是用来"招揽" 客户端的 ;
    public TcpEchoServer(int port) throws IOException {
        this.socket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            // 1. 通过accept ,从内核中拿已经建立好的 连接对象 拿到 应用程序
            // 建立连接的细节, 都是内核完成的, 无需我们手动指定
            Socket clientSocket = socket.accept();      // 这里的socket,是用来后续和连接的客户端通信的 ;
            processConnection(clientSocket);
        }
    }
      // 通过这个方法 , 来处理 当前连接 ;
    private void processConnection(Socket clientSocket) throws IOException {
          // 打印日志 , 表示有客户端连接上了
        System.out.printf("[%s,%d] 客户端上线\n" , clientSocket.getInetAddress() , clientSocket.getPort());
        // 输入和输出都是字节流的
        //使用try 避免后面忘了close
        try(InputStream inputStream = clientSocket.getInputStream() ;
            OutputStream outputStream = clientSocket.getOutputStream()){
           //客户端可能发送多个数据 , 使用while 来循环处理
            while (true){
                // 使用scanner 来配合 inputStream , 方便读取 ;
                Scanner scan = new Scanner(inputStream) ;
                if(!scan.hasNext()){
                    //如果没有数据了表示, 客户端连接断开了 ; 此时停止 ;
                    // 打印日志
                    System.out.printf("[%s,%d] 客户端下线\n" , clientSocket.getInetAddress() , clientSocket.getPort());
                    break;
                }
                // 使用next()来读取, next的读取以"空白符"结束 ,这里我们可以规定客户端以 \n ,作为结束标志
                //1. 读取请求 ,并解析
             String request = scan.next() ;
              // 2. 计算响应 process处理请求
              String response =   process(request);
              // 3. 把响应发送给客户端;
                // OutputStream可以有两种方法,将数据写回到客户端 ;
                // 可以把响应转换成字节数组,写入到OutputStream , 但是 数据最后 没有 \n
               // outputStream.write(response.getBytes());
                // 可以使用 PrintWriter 把 OutputStream给包裹一下,来写入字符串
                PrintWriter writer = new PrintWriter(outputStream) ;
                // 此时这里输出的位置就不是控制台,而是 OutputStream的流对象,就是 clientSocket
                // 这样数据就发送给客户端了 ;
                // 使用println,也是 让数据最后带有 \n , 这样在客户端就可以使用 scan.next()来读取 ;
                 writer.println(response);
                 // 刷新缓冲区,避免数据没有成功发送
                writer.flush();

                // 4. 打印日志 ,包含请求和响应;
                System.out.printf("[%s,%d]request= %s , response= %s" , clientSocket.getInetAddress() ,
                        clientSocket.getPort() , request , response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            clientSocket.close();
        }


    }
    //回显,请求就是响应
    private String process(String request) {
        return request ;
    }
}
